在前兩天的 Kubernetes 三兄弟 - 實戰做一個 Service (二)
我們介紹了 Service
這個元件,並且在利用他讓集群中的 Pod
可以被外部的我們存取。然而每個物件都需要指定對外的 port number
以及 Node 上的 port mapping
,這就代表 愈多的 Service 就要管理愈多的 port number
,而且現在任何的網站上面如果還需要加上 port number
實用性實在大打折扣。
Ingress 可以幫我們統一對外的 port number
,並且根據 hostname 或是 pathname 決定請求要轉發到哪個 Service
上成為更上層的 LoadBalancer
,並且 Kubernetes Ingress
會統一打開 http 的 80 port 以及 https 的 443 port,解決剛才提到的 port number 紊亂不一的問題。
Ingress 負責的事情主要被定義為下面幾項:
hostname
。在本地的 docker-desktop
上我們只需要運行下列設定檔,Kubernetes 就會幫我們建立一個 ingress-nginx
的 namespace,並且運行起相關服務:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.1/deploy/static/provider/cloud/deploy.yaml
------------------------------
namespace/ingress-nginx unchanged
serviceaccount/ingress-nginx configured
serviceaccount/ingress-nginx-admission configured
role.rbac.authorization.k8s.io/ingress-nginx configured
role.rbac.authorization.k8s.io/ingress-nginx-admission configured
clusterrole.rbac.authorization.k8s.io/ingress-nginx configured
clusterrole.rbac.authorization.k8s.io/ingress-nginx-admission configured
rolebinding.rbac.authorization.k8s.io/ingress-nginx configured
rolebinding.rbac.authorization.k8s.io/ingress-nginx-admission configured
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx configured
clusterrolebinding.rbac.authorization.k8s.io/ingress-nginx-admission configured
configmap/ingress-nginx-controller configured
service/ingress-nginx-controller created
service/ingress-nginx-controller-admission created
deployment.apps/ingress-nginx-controller created
job.batch/ingress-nginx-admission-create created
job.batch/ingress-nginx-admission-patch created
ingressclass.networking.k8s.io/nginx configured
validatingwebhookconfiguration.admissionregistration.k8s.io/ingress-nginx-admission configured
檢查是否成功運作:
kubectl get all -n ingress-nginx
------------------------------
NAME READY STATUS RESTARTS AGE
pod/ingress-nginx-admission-create-rf8cl 0/1 Completed 0 7m4s
pod/ingress-nginx-admission-patch-mzmc8 0/1 Completed 0 7m4s
pod/ingress-nginx-controller-778667bc4b-twt6n 1/1 Running 0 7m4s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/ingress-nginx-controller LoadBalancer 10.105.184.158 localhost 80:30205/TCP,443:31820/TCP 7m5s
service/ingress-nginx-controller-admission ClusterIP 10.106.69.252 <none> 443/TCP 7m4s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/ingress-nginx-controller 1/1 1 1 7m4s
NAME DESIRED CURRENT READY AGE
replicaset.apps/ingress-nginx-controller-778667bc4b 1 1 1 7m4s
NAME COMPLETIONS DURATION AGE
job.batch/ingress-nginx-admission-create 1/1 5s 7m4s
job.batch/ingress-nginx-admission-patch 1/1 5s 7m4s
關於 Ingress
的實際應用,官方有提供幾種方式讓我們用 URL
控制並連接到我們指定的服務。
現有的 Kubernetes 允許我們直接暴露 單一個 Service
。現在我們依然可以透過 ingress 的 defaultBackend
辦到這件事,代表規範條件以外的流量通通都會遵守 defaultBackend
規則分配到對應服務。
準備相關設定檔:
// deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo-deployment
labels:
type: demo
spec:
replicas: 2
selector:
matchLabels:
type: demo
template:
metadata:
labels:
type: demo
spec:
containers:
- name: foo
image: mikehsu0618/foo
ports:
- containerPort: 8080
// service.yaml
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
type: demo
type: NodePort // 這裡我們將能直接暴露端口的 `Loadbalancer` 改成 `NodePort`
ports:
- protocol: TCP
port: 8000
targetPort: 8080
nodePort: 30390
// ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
ingressClassName: nginx
defaultBackend:
service:
name: my-service
port:
number: 8000
在上面的 ingress.yaml
我們設定了 defaultBackend
讓所有流量都預設導到 my-service
中的 8000 port
,形成了一條從 loadbalancer
→ services
→ pods
的路徑。
執行以上設定檔:
kubectl apply -f deployment.yaml,service.yaml,ingress.yaml
----------------------------
deployment.apps/foo-deployment unchanged
service/my-service unchanged
ingress.networking.k8s.io/my-ingress unchanged
查看服務狀況:
kubectl get all
----------------------------
NAME READY STATUS RESTARTS AGE
pod/foo-deployment-6bbf665b47-6769n 1/1 Running 0 41m
pod/foo-deployment-6bbf665b47-96khw 1/1 Running 0 41m
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 27d
service/my-service NodePort 10.108.203.7 <none> 8000:30390/TCP 41m
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/foo-deployment 2/2 2 2 41m
NAME DESIRED CURRENT READY AGE
replicaset.apps/foo-deployment-6bbf665b47 2 2 2 41m
查看 Ingress :
kubectl get ingress
----------------------------
NAME CLASS HOSTS ADDRESS PORTS AGE
my-ingress nginx * localhost 80 42m
成功將啟動了一個 localhost:80 的負載均衡器~
實際測試:
curl localhost
----------------------------
{"data":"Hello foo"}
一個 fanout
可以根據請求的 URL 將來自同一個 IP 地址的流量轉到到多個 Service。並且實現以下配置:
準備相關設定檔:
// deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: foo-deployment
labels:
type: foo-demo
spec:
replicas: 2
selector:
matchLabels:
type: foo-demo
template:
metadata:
labels:
type: foo-demo
spec:
containers:
- name: foo
image: mikehsu0618/foo
ports:
- containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bar-deployment
labels:
type: bar-demo
spec:
replicas: 1
selector:
matchLabels:
type: bar-demo
template:
metadata:
labels:
type: bar-demo
spec:
containers:
- name: bar
image: mikehsu0618/bar
ports:
- containerPort: 8080
// service.yaml
apiVersion: v1
kind: Service
metadata:
name: foo-service
spec:
type: NodePort
selector:
type: foo-demo
ports:
- protocol: TCP
port: 8000
targetPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: bar-service
spec:
type: NodePort
selector:
type: bar-demo
ports:
- protocol: TCP
port: 8000
targetPort: 8080
// ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
ingressClassName: nginx
rules:
- host: foo.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: foo-service
port:
number: 8000
- host: bar.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: bar-service
port:
number: 8000
可以在上面的設定檔看到我們用 ingress
產生出的 virsual hosting
並且使不同的網域對應到不同的 Service
,實現預期的 fanout
效果。
讓我們運行以上設定檔:
kubectl apply -f deployment.yaml,service.yaml,ingress.yaml
deployment.apps/foo-deployment configured
deployment.apps/bar-deployment configured
service/foo-service configured
service/bar-service configured
ingress.networking.k8s.io/my-ingress configured
查看 ingress 詳細資訊:
kubectl describe ingress my-ingress
----------------------------
Name: my-ingress
Labels: <none>
Namespace: default
Address: localhost
Ingress Class: nginx
Default backend: <default>
Rules:
Host Path Backends
---- ---- --------
foo.com
/ foo-service:8000 (10.1.1.169:8080,10.1.1.170:8080)
bar.com
/ bar-service:8000 (10.1.1.168:8080)
Annotations: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Sync 7m35s (x4 over 15m) nginx-ingress-controller Scheduled for sync
Ingress 已經成功的替我們架起了 foo.com bar.com 兩個虛擬網域,並幫我們把服務連接到對應的 Service
上~
因為我們是在本地上架起虛擬網域的,所以我們需要讓以上兩個網域反向代理到本地 127.0.0.1
上,所以我們這時必須去調整 /etc/hosts
檔本地才能順利吃到路徑請求:
sudo vim /etc/hosts
// 在檔案中插入以下需要映射的網域
127.0.0.1 foo.com
127.0.0.1 bar.com
// 在鍵盤中手動輸入下列字元來儲存!
:wq!
接著來實際測試:
curl http://foo.com
{"data":"Hello foo"}
curl http://bar.com
{"data":"Hello bar"}
大功告成!
感謝願意看到這裡的同鞋們,到這裡我們可以說是已經初窺 Kubernetes
的門徑,熟悉 docker 的人已經有能力可以在本地 run 起自己想要的服務,並且配置 URL
路徑實現負載均衡。說說我自己的收穫,因為接觸了 Kubernetes
讓我開始學習思考如何實現一套微服務系統,他的出現對我這個之前總是在寫單體式應用的小廢廢來說,對分佈式架構有個更清晰的輪廓並且深深著迷,還有太多東西可以學習了,就讓我們繼續堅持下去吧。
千呼萬喚始出來!鐵人賽系列「從異世界歸來發現只剩自己不會 Kubernetes」同名改編作品出版了!
感謝所有交流指教的各路英雄,也感謝願意點閱文章的各位,如果能幫助到任何人都將會是我的榮幸。
本書內容改編自第 14 屆 iThome 鐵人賽 DevOps 組的優選系列文章《從異世界歸來發現只剩自己不會 Kubernetes》。此書是一本綜合性的指南,針對想要探索認識 Kubernetes 的技術人員而生。無論是初涉此領域的新手,還是已有深厚經驗的資深工程師,本書都能提供你所需的知識和技能。
「這本書不僅提供了豐富的範例程式碼和操作指南,讓身為工程師的我們能實際操作來加深認知;更重要的是,它教會我如何從後端工程師的角度去思考和應用 Kubernetes。從容器的生命週期、資源管理到部署管理,每一章都與我們的日常開發工作息息相關。」
──── 雷N │ 後端工程師 / iThome 鐵人賽戰友
天瓏連結: 從異世界歸來發現只剩自己不會 Kubernetes:初心者進入雲端世界的實戰攻略!
相關文章:
相關程式碼同時收錄在:
https://github.com/MikeHsu0618/2022-ithelp/tree/master/Day9
Reference
Kubernetes Documentation-ingress
[Kubernetes] Resource Object 概觀
請問ingress.yaml 裏的ingressClassName: nginx 是不是和
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.2.1/deploy/static/provider/cloud/deploy.yaml
有關係? 還是隨便給他一個名字?
在2. Simple Fanout and Visual hosting 的ingress.yaml 裏,如果我想給它一個固定ip address,例如: 192.1.10.2 是不是在spec.rules.host那行輸入192.1.10.2。
如果我想在根據不是網址能夠去到不同的backend service,是不是在spec.rules.http.paths: 裏輸入,例如: foo. 當我們在網頁輸192.1.10.2/foo,就能夠去到foo-service?
nginx-ingress
,如有其他需求可以而外安裝如 AWS 的 ALB
ingress controller。